package com.example.springboot.ytest.ytest;

import java.io.IOException;
import java.net.URL;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.example.springboot.ytest.ytool.AlibabaOssUtil;
import com.example.springboot.ytest.ytool.DateUtil;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;

class TestBean{
    private Long id;
    private String s;
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getS() {
        return s;
    }
    public void setS(String s) {
        this.s = s;
    }
}

@Controller
// 自测如果这里只写 @RequestMapping("/") 则方法前的  @RequestMapping 可写成  @RequestMapping("/XXX") 也可以写成 @RequestMapping("XXX")
// 注意 @RequestMapping 拼出来的 url 是区分大小写的
@RequestMapping("/CtrlGetPost")
public class CtrlGetPost extends BaseController {
    
    private Logger loggerBase = LoggerFactory.getLogger(this.getClass());
    
    @Autowired
    private PasswordUtil passwordUtil;
    
    // url 例：http://{{ytest}}/ytest/rest/CtrlGetPost/get2?id=12333只&username=abbb
    @RequestMapping("/get1")    // 自测如果类上的 @RequestMapping("/") 则这里可以不用 /也可以用
    public @ResponseBody String Get1(HttpServletRequest request) {// 不加 @ResponseBody 将默认返回XXX.jsp 页面的名称，不存在则出错
        String id = request.getParameter("id");
        URL urlOfClass = this.getClass().getClassLoader().getResource("org/slf4j/spi/LocationAwareLogger.class");
        System.out.println(urlOfClass);
        return "id = "+id;
    }

    @RequestMapping(value="/get2",method = RequestMethod.GET)
    public @ResponseBody String Get2(@RequestParam("username") String username, @RequestParam("id") String id) {
        return "userName = " + username + ", id = " + id;
    }
    
    @RequestMapping("/get3/{id}")
    public @ResponseBody String getProductById(@PathVariable("id") int id) {
        return "get3: id = " + id;
    }
    
    @RequestMapping("/getReDirect/{id}")
    public @ResponseBody String getReDirect(HttpServletResponse response, @PathVariable("id") int id) {
        String result = "getReDirect";
        try {
//          response.sendRedirect("../get3/"+id);   // 相对当前路径
            response.sendRedirect("/ytest/rest/CtrlGetPost/get3/"+id);  // 绝对路径，从服务器地址开始
        } catch (IOException e) {
            e.printStackTrace();
            result += (" err: " + e.getMessage());
        }
        return result;
    }
    
    @RequestMapping("/get4")    // 自测如果类上的 @RequestMapping("/") 则这里可以不用 /也可以用
    public @ResponseBody String Get4(int id) {// 不加 @ResponseBody 将默认返回XXX.jsp 页面的名称，不存在则出错
        return "id = "+id;
    }
    
    @RequestMapping("/getBool") // 自测如果类上的 @RequestMapping("/") 则这里可以不用 /也可以用
    public @ResponseBody String GetBool(Boolean bool) {// 不加 @ResponseBody 将默认返回XXX.jsp 页面的名称，不存在则出错
        return "bool = "+bool;
    }
    
    @RequestMapping(value = "/post1", method = RequestMethod.POST)
    public @ResponseBody String Post1(HttpServletRequest request, HttpServletResponse response,
            @RequestParam(value = "para", defaultValue = "{}") String para) throws IOException {
        String requestStr = IOUtils.toString(request.getInputStream());
        if(StringUtils.isNotBlank(requestStr)) {
            JSONObject jsonObject = JSONObject.parseObject(requestStr);
            System.out.println("para: "+request.getParameterMap());
            System.out.println("json2: "+jsonObject);
        }
        return "get: " + para;
    }
    
    @RequestMapping(value = "/postJsonMap", method = RequestMethod.POST)
    public @ResponseBody String postJsonMap(@RequestBody Map<String, Object> map) {
        
        Integer id = MapUtils.getInteger(map, "i");
        Boolean b = MapUtils.getBoolean(map, "b");
        Boolean isMajor = MapUtils.getBoolean(map, "isMajor");
        Boolean issMajor = MapUtils.getBoolean(map, "issMajor");
        String str = MapUtils.getString(map, "str");
        return id +" "+b+" "+isMajor+" "+issMajor+" "+str;
    }
    
    @RequestMapping(value = "/postjsonObj", produces = {"application/json;charset=UTF-8"}, method = RequestMethod.POST)
    public @ResponseBody PostClass postjsonObj(@RequestBody PostClass ps, PostClass ps2) throws IOException {
        loggerBase.info("ps: {}", JSON.toJSONString(ps));   // 这种是取 post json
        loggerBase.info("ps2: {}", JSON.toJSONString(ps2)); // 这种是取 get的
        return ps;
    }
    
    @RequestMapping(value = "/postjsonParam", produces = {"application/json;charset=UTF-8"}, method = RequestMethod.POST)
    public @ResponseBody String postjsonParam(HttpServletRequest request) {
        loggerBase.info(this.getParameter(request, "name"));
        return this.getParameter(request, "name");
    }
    
    /**
     * postman x-www-form-urlencoded 方式
     * @author: yeyi
     * @date: 2019年6月28日
     */
    @RequestMapping(value = "/postParam", method = RequestMethod.POST)
    public @ResponseBody String postParam(Long id, String s) {
        return id + " " + s;
    }
    
    /**
     * postman x-www-form-urlencoded 方式
     * 注意 PostClass 必须要有 public 的构造函数且必须要有 get set
     * @author: yeyi
     * @date: 2019年6月28日
     */
    @RequestMapping(value = "/postObj", method = RequestMethod.POST)
    public @ResponseBody String postObj(PostClass ps) {
        return JSON.toJSONString(ps);
    }
    
    /**
     * 这种方式不行
     * @author: yeyi
     * @date: 2019年6月28日
     */
    @RequestMapping(value = "/postMap", method = RequestMethod.POST)
    public @ResponseBody String postMap(Map<String, Object> map) {
        return JSON.toJSONString(map);
    }
    
    /**
     * 接口重定向
     * @param request
     * @param response
     * @param para
     * @return
     * @throws IOException
     * @author: yeyi
     * @date: 2019年6月28日
     */
    @RequestMapping(value = "/postRedirect", method = RequestMethod.POST)
    public @ResponseBody String PostRedirect(HttpServletRequest request, HttpServletResponse response,
            @RequestParam(value = "para", defaultValue = "{}") String para) throws IOException {
        String result = "getReDirect";
        try {
//            response.sendRedirect("../post1");  // post 的参数无法传到重定向中,那重定向的接口不能是POST
          response.sendRedirect("../get1");
        } catch (IOException e) {
            e.printStackTrace();
            result += (" err: " + e.getMessage());
        }
        return result;
    }
    
    /**
     * 前端可以传 true false 0 1 
     * @param bool 
     * @param bool2
     * @author: yeyi
     * @date: 2019年6月28日
     */
    @RequestMapping(value = "/postbool", method = RequestMethod.POST)
    public @ResponseBody String Postbool(boolean bool, boolean bool2){
        return "bool: "+bool+" bool2: "+bool2;
    }
    
    /**
     * 传 id 数组，postman 要用 application/x-www-form-urlencoded 方式传
     * @param ids
     * @author: yeyi
     * @date: 2018年11月15日
     */
	@RequestMapping(value = "/postArray", method = RequestMethod.POST)
	public @ResponseBody String PostArray(@RequestParam("ids") List<Long>ids) throws IOException {
		return JSON.toJSONString(ids);
	}
	
	/**
	 * json 方式传数组, postman 传的 json 格式不用大括号：[1,2,3333]
	 * @param ids
	 * @author: yeyi
	 * @date: 2019年6月26日
	 */
	@RequestMapping(value = "/postArrayJson", method = RequestMethod.POST)
	public @ResponseBody String postArrayJson(@RequestBody List<Long>ids) throws IOException {
		return JSON.toJSONString(ids);
	}

	/**
	 * 是否是常见英文单词
	 * @param str
	 * @return
	 * @author: yeyi
	 * @date: 2019年6月28日
	 */
    @RequestMapping(value = "/isword")
    public @ResponseBody String isword(String str){
        return passwordUtil.isWords(str)+"";
    }

    /**
     * 密码是否符合复杂度要求
     * @param account
     * @param pwd
     * @return
     * @author: yeyi
     * @date: 2019年6月28日
     */
    @RequestMapping(value = "/checkpwd")
    public @ResponseBody String checkpwd(String account, String pwd){
        return passwordUtil.checkPwd(pwd, account);
    }
    
    /**
     * 批量上传文件（图片）
     * 如果文件名 key 重复则会覆盖之前上传的内容(包括过期时间)，因此如果不希望覆盖必须上传者自己管理 key 不重复
     * key 使用UTF-8编码，长度必须在1-1023字节之间，不能以“/”或者“\”字符开头。
     * @param millisecond 过期时间戳，毫秒，最小不能小于1小时，非必传
     * @param year 过期时间，年，最小不能小于1年（没填写  millisecond 才生效），非必传
     * 若没填写任何过期参数(millisecond, year)，默认100年(实际代码跑出来50年，还不知道为什么)
     * @return 图片 url list
     * @author yeyi
     * @date 2019年7月18日
     */
    @RequestMapping(value = "/files")
    public List<String> files(HttpServletRequest request, Long millisecond, Integer year){
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
        
        // millisecond 为主，没有再看 year
        final long minMillis = System.currentTimeMillis()+1000*3600; // 最小不能小于一小时
        if(null==millisecond) {
            if(null==year || year<1) {
                millisecond = 1000*3600*24*365L*100;
            } else {
                millisecond = 1000*3600*24*365L*year;
            }
        } else {
            if(millisecond<minMillis) {
                millisecond = minMillis;
            }
        }
        Date expiration = new Date(millisecond);
        loggerBase.info("uploadFil expiration: {}", DateUtil.dateToStr(expiration));
        
        List<String> result = Lists.newLinkedList();
        for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
            MultipartFile mf = entity.getValue();
            String fileKey = entity.getKey();
            if(StringUtils.isEmpty(fileKey) || fileKey.length()>1023) {
                loggerBase.error("uploadFil key err: {}", fileKey);
                continue;
            }
            if('\\'==fileKey.charAt(0) || '/'==fileKey.charAt(0)) {
                loggerBase.error("uploadFil key can't start with slash: {}", fileKey);
                continue;
            }
            
            try {
                URL url = AlibabaOssUtil.uploadInputStream(mf.getInputStream(), fileKey, expiration);
                if(null==url || StringUtils.isEmpty(url.toString())) {
                    loggerBase.error("uploadInputStrea empty: {},{}", fileKey, mf.getOriginalFilename());
                    continue;
                }
                result.add(url.toString());
            } catch (Exception e) {
                loggerBase.error("uploadInputStrea err: ", e);
            }
        }
        
        return result;
    }
}